# =============================================================================
# Definitions used in setup.py
# =============================================================================
set(NRN_SRCDIR ${PROJECT_SOURCE_DIR})
set(NRNPYTHON_DEFINES "")

# ~~~
# If NRN_PYTHON_DYNAMIC then the following three will be determined from the
# actual pyexe that runs setup.py
# ~~~
set(NRNPYTHON_EXEC ${PYTHON_EXECUTABLE})
set(NRNPYTHON_PYVER ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR})
set(npy_pyver10 "")

# reset since no " allowed
set(PACKAGE_VERSION ${PROJECT_VERSION})
set(NRN_LIBDIR ${CMAKE_INSTALL_PREFIX}/lib)

# set by IV's cmake module
set(IV_LIBDIR "${IV_INCLUDE_DIR}/../lib")

# no suffix for readline
set(READLINE_SOSUFFIX "")

if(NRN_ENABLE_RX3D)
  set(BUILD_RX3D "1")
else()
  set(BUILD_RX3D "0")
endif()

if(NRN_ENABLE_INTERVIEWS)
  set(IVHINES "interviews")
else()
  set(IVHINES "")
endif()

# use compiler from CMake
set(CC ${CMAKE_C_COMPILER})
set(CXX ${CMAKE_CXX_COMPILER})

# =============================================================================
# Options that get expanded to comments
# =============================================================================
set(BUILD_NRNMPI_DYNAMIC_FALSE "#")
set(BUILD_NRNPYTHON_DYNAMIC_TRUE "")
set(BUILD_NRNPYTHON_DYNAMIC_FALSE "#")

if(NRN_ENABLE_PYTHON_DYNAMIC)
  if("${NRN_PYTHON_DYNAMIC}" STREQUAL "")
    set(NRN_PYTHON_EXE_LIST
        ${PYTHON_EXECUTABLE}
        CACHE INTERNAL "" FORCE)
  else()
    set(NRN_PYTHON_EXE_LIST
        ${NRN_PYTHON_DYNAMIC}
        CACHE INTERNAL "" FORCE)
  endif()
else()
  set(BUILD_NRNPYTHON_DYNAMIC_TRUE "#")
  set(BUILD_NRNPYTHON_DYNAMIC_FALSE "")
  set(NRN_PYTHON_EXE_LIST
      ${PYTHON_EXECUTABLE}
      CACHE INTERNAL "" FORCE)
endif()

if(NRN_MACOS_BUILD)
  set(MAC_DARWIN_TRUE "")
  set(MAC_DARWIN_FALSE "#")
  set(setup_extra_link_args "#extra_link_args")
else()
  set(MAC_DARWIN_TRUE "#")
  set(MAC_DARWIN_FALSE "")
  set(setup_extra_link_args "extra_link_args")
endif()

if(NRN_WINDOWS_BUILD)
  set(BUILD_MINGW_TRUE "")
  set(BUILD_MINGW_FALSE "#")
else()
  set(BUILD_MINGW_TRUE "#")
  set(BUILD_MINGW_FALSE "")
endif()

if(NRN_ENABLE_MEMACS)
  set(BUILD_MEMACS_TRUE "")
else()
  set(BUILD_MEMACS_TRUE "#")
endif()

# rxdmath libraries (always build)
add_library(rxdmath SHARED ${CMAKE_CURRENT_SOURCE_DIR}/rxdmath.c)
install(TARGETS rxdmath DESTINATION ${NRN_INSTALL_SHARE_LIB_DIR})

# =============================================================================
# nrnpython libraries (one lib per python)
# =============================================================================

set(nrnpython_lib_list)

# user has selected dynamic python support (could be multiple versions)
if(NRN_ENABLE_PYTHON_DYNAMIC)
  set(INCLUDE_DIRS
      .
      ../oc
      ../nrnoc
      ../ivoc
      ../nrniv
      ../ivos
      ../gnu
      ../mesch
      ../nrnmpi
      ${PROJECT_BINARY_DIR}/src/nrnpython
      ${PROJECT_BINARY_DIR}/src/ivos
      ${PROJECT_BINARY_DIR}/src/oc
      ${IV_INCLUDE_DIR})

  if(LINK_AGAINST_PYTHON)
    list(LENGTH NRN_PYTHON_EXE_LIST _num_pythons)
    math(EXPR num_pythons "${_num_pythons} - 1")
    foreach(val RANGE ${num_pythons})
      list(GET NRN_PYTHON_VER_LIST ${val} pyver)
      list(GET NRN_PYTHON_INCLUDE_LIST ${val} pyinc)
      list(GET NRN_PYTHON_LIB_LIST ${val} pylib)
      add_library(nrnpython${pyver} SHARED ${NRN_NRNPYTHON_SRC_FILES})
      target_include_directories(nrnpython${pyver} BEFORE PUBLIC ${pyinc} ${INCLUDE_DIRS})
      target_link_libraries(nrnpython${pyver} nrniv_lib ${pylib} ${Readline_LIBRARY})
      add_dependencies(nrnpython${pyver} nrniv_lib)
      list(APPEND nrnpython_lib_list nrnpython${pyver})
      install(TARGETS nrnpython${pyver} DESTINATION ${NRN_INSTALL_SHARE_LIB_DIR})
    endforeach()
  else()
    # build python2 library and install it
    if(NRNPYTHON_INCLUDE2)
      add_library(nrnpython2 SHARED ${NRN_NRNPYTHON_SRC_FILES})
      target_include_directories(nrnpython2 BEFORE PUBLIC ${NRNPYTHON_INCLUDE2} ${INCLUDE_DIRS})
      add_dependencies(nrnpython2 nrniv_lib)
      list(APPEND nrnpython_lib_list nrnpython2)
      install(TARGETS nrnpython2 DESTINATION ${NRN_INSTALL_SHARE_LIB_DIR})
    endif()

    # build python3 library and install it
    if(NRNPYTHON_INCLUDE3)
      add_library(nrnpython3 SHARED ${NRN_NRNPYTHON_SRC_FILES})
      add_dependencies(nrnpython3 nrniv_lib)
      list(APPEND nrnpython_lib_list nrnpython3)
      target_include_directories(nrnpython3 BEFORE PUBLIC ${NRNPYTHON_INCLUDE3} ${INCLUDE_DIRS})
      install(TARGETS nrnpython3 DESTINATION ${NRN_INSTALL_SHARE_LIB_DIR})
    endif()
  endif()
endif()

# Install package files that were created in build (e.g. .py.in)
install(DIRECTORY ${PROJECT_BINARY_DIR}/share/lib/python
        DESTINATION ${NRN_LIBDIR}
        FILES_MATCHING PATTERN *.py PATTERN *.so PATTERN *.dylib)


# =============================================================================
# If NEURON python module installation is enabled
# =============================================================================
if(NRN_ENABLE_MODULE_INSTALL)

  # All variables are set, prepare setup.py for python module install
  nrn_configure_file(setup.py src/nrnpython)

  # Setup MinGW toolchain for setuptools
  if(MINGW)
    file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/setup.cfg "[build]\ncompiler=mingw32")

    # replace windows path of the form C:/msys64 to C:\msys64
    string(REPLACE ":/" ":\\\\" module_install_opts "${NRN_MODULE_INSTALL_OPTIONS}")
    set(NRN_MODULE_INSTALL_OPTIONS
        "${module_install_opts}"
        CACHE INTERNAL "" FORCE)
  endif()

  # Here and for the neuron/rxd/geometry3d extensions, we build the neuron module in lib/python
  set(NRN_PYTHON_BUILD_LIB
      ${PROJECT_BINARY_DIR}/lib/python
      CACHE INTERNAL "" FORCE)

  # ~~~
  # To tickle setup.py into actually rebuilding if dependencies change,
  # need to copy inithoc.cpp in from source to binary dir if any module
  # dependent changes and make a custom target as well.
  # ~~~
  set(binary_dir_filename ${CMAKE_CURRENT_BINARY_DIR}/inithoc.cpp)
  set(source_dir_filename ${CMAKE_CURRENT_SOURCE_DIR}/inithoc.cpp)
  set(inithoc_hdeps
      ${CMAKE_CURRENT_SOURCE_DIR}/../oc/nrnmpi.h ${CMAKE_CURRENT_BINARY_DIR}/../oc/nrnmpiuse.h
      ${CMAKE_CURRENT_BINARY_DIR}/../oc/nrnpthread.h ${CMAKE_CURRENT_BINARY_DIR}/nrnpython_config.h)

  add_custom_command(
    OUTPUT ${binary_dir_filename}
    COMMAND cp ${source_dir_filename} ${binary_dir_filename}
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
    DEPENDS ${source_dir_filename} ${CMAKE_CURRENT_BINARY_DIR}/setup.py ${inithoc_hdeps})

  add_custom_target(
    hoc_module ALL
    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
    DEPENDS ${binary_dir_filename})

  # ~~~
  # For DYNAMIC python, inithoc module name convention is different for
  # autotools version and cmake. So nrnpy_hoc.cpp and inithoc.cpp need
  # to know whether they are compiled via the cmake or autotools build system.
  # (note: see also for inithoc.cpp via setup.py)
  # ~~~
  set_property(
    SOURCE ${PROJECT_SOURCE_DIR}/src/nrnpython/nrnpy_hoc.cpp
           ${PROJECT_SOURCE_DIR}/src/nrnpython/nrnpython.cpp
    APPEND
    PROPERTY COMPILE_DEFINITIONS NRNCMAKE)

  # =============================================================================
  # Copy necessary files to build directory
  # =============================================================================

  add_custom_command(
    TARGET hoc_module PRE_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/share/lib
            ${NRN_BUILD_SHARE_DIR}/lib
    COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/share/lib
            ${PROJECT_BINARY_DIR}/share/nrn/lib
    COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/share/demo
            ${PROJECT_BINARY_DIR}/share/nrn/demo)

  # =============================================================================
  # Build python module
  # =============================================================================
  # for each python detected / provided by user, install module at install time
  foreach(pyexe ${NRN_PYTHON_EXE_LIST})
    add_custom_command(
      TARGET hoc_module POST_BUILD
      COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/inithoc.cpp
              ${CMAKE_CURRENT_BINARY_DIR}/inithoc.cpp
      COMMAND ${pyexe} setup.py --quiet build --build-lib=${NRN_PYTHON_BUILD_LIB}
      WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
      COMMENT "Building python module with: ${pyexe}")
  endforeach(pyexe)

  add_dependencies(hoc_module nrniv_lib ${nrnpython_lib_list})

  #~~~
  # neuron module (possibly with multiple extension versions) was built
  # in NRN_PYTHON_BUILD_LIB. Not a problem if install overwrites multiple
  # times to same install folder or if each install ends up in different
  # place.
  #~~~
  file(
    WRITE ${CMAKE_CURRENT_BINARY_DIR}/neuron_module_install.sh
    "\
#!bash\n\
echo 'Installing python module using:'\n\
set -ex\n\
cd ${CMAKE_CURRENT_BINARY_DIR}\n\
$1 setup.py --quiet build --build-lib=${NRN_PYTHON_BUILD_LIB} install ${NRN_MODULE_INSTALL_OPTIONS}\n\
")
  foreach(pyexe ${NRN_PYTHON_EXE_LIST})
    install(
      CODE "execute_process(COMMAND bash ${CMAKE_CURRENT_BINARY_DIR}/neuron_module_install.sh ${pyexe})")
  endforeach(pyexe)
endif()
